home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume16 / pcomm2 / part07 < prev    next >
Encoding:
Internet Message Format  |  1988-09-14  |  48.5 KB

  1. Path: bbn.com!rsalz
  2. From: rsalz@uunet.uu.net (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v16i012:  Modem communications package, Part07/08
  5. Message-ID: <1064@fig.bbn.com>
  6. Date: 13 Sep 88 16:45:40 GMT
  7. Lines: 2182
  8. Approved: rsalz@uunet.UU.NET
  9.  
  10. Submitted-by: Emmet P Gray <fthood!egray>
  11. Posting-number: Volume 16, Issue 12
  12. Archive-name: pcomm2/part07
  13.  
  14. #! /bin/sh
  15. # This is a shell archive, meaning:
  16. # 1. Remove everything above the #! /bin/sh line.
  17. # 2. Save the resulting text in a file.
  18. # 3. Execute the file with /bin/sh (not csh) to create:
  19. #    vcs.c
  20. #    x_ascii.c
  21. #    x_batch.c
  22. #    x_extrnl.c
  23. #    x_menu.c
  24. #    x_rcv.c
  25. export PATH; PATH=/bin:/usr/bin:$PATH
  26. echo shar: "extracting 'vcs.c'" '(10169 characters)'
  27. if test -f 'vcs.c'
  28. then
  29.     echo shar: "will not over-write existing file 'vcs.c'"
  30. else
  31. sed 's/^X//' << \SHAR_EOF > 'vcs.c'
  32. X/*
  33. X * Routines for VCS detection.
  34. X */
  35. X
  36. X#include <stdio.h>
  37. X#include <curses.h>
  38. X#include "config.h"
  39. X#ifndef OLDCURSES
  40. X#include <term.h>
  41. X#endif /* OLDCURSES */
  42. X#include "vcs.h"
  43. X
  44. Xstatic int putc_cnt;
  45. Xstatic char putc_buf[VCS_SIZE];
  46. X
  47. X/*
  48. X * Test for possible VCS (video command sequence).  A character return
  49. X * code means no match.  An return code greater than 255 means a VCS
  50. X * was found.
  51. X */
  52. X
  53. Xint
  54. Xvcs_filter(c)
  55. Xchar c;
  56. X{
  57. X    extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_leadin[NUM_VCS];
  58. X    extern int num_leadin;
  59. X    static int buf[VCS_SIZE];
  60. X    static int ptr = 0;
  61. X    register int i;
  62. X    int maybe, possible;
  63. X
  64. X                    /* see if possible */
  65. X    possible = 0;
  66. X    if (ptr == 0) {
  67. X                    /* lead-in less than a space */
  68. X        if (c >= ' ')
  69. X            return(c & 0xff);
  70. X                    /* check the list */
  71. X        for (i=0; i<num_leadin; i++) {
  72. X            if (c == vcs_leadin[i]) {
  73. X                possible++;
  74. X                break;
  75. X            }
  76. X        }
  77. X        if (!possible)
  78. X            return(c & 0xff);
  79. X    }
  80. X
  81. X                    /* build the string */
  82. X    buf[ptr++] = c;
  83. X    buf[ptr] = -1;
  84. X                    /* test for match */
  85. X    maybe = 0;
  86. X    for (i=0; i<NUM_VCS; i++) {
  87. X        switch (match_codes(buf, vcs_codes[i], i)) {
  88. X            case YES:
  89. X                ptr = 0;
  90. X                return(i+256);
  91. X            case NO:
  92. X                break;
  93. X            case MAYBE:
  94. X                maybe++;
  95. X                break;
  96. X        }
  97. X    }
  98. X                    /* abandon what you've got */
  99. X    if (maybe && ptr == VCS_SIZE-1) {
  100. X        ptr = 0;
  101. X        return(c & 0xff);
  102. X    }
  103. X                    /* hang on, wait and see */
  104. X    if (maybe)
  105. X        return(MAYBE);
  106. X                    /* a clean miss */
  107. X    ptr = 0;
  108. X    return(c & 0xff);
  109. X}
  110. X
  111. X/*
  112. X * See if the two integer arrays "match".  Character parameters are
  113. X * designated by codes > 1000 and ASCII digit parameters are designated
  114. X * by codes > 2000.  Uses a simple linear search, so if NUM_VCS grows
  115. X * this routine will have to mature a bit.
  116. X */
  117. X
  118. Xstatic int
  119. Xmatch_codes(test, code, k)
  120. Xint test[], code[], k;
  121. X{
  122. X    extern int vcs_param[NUM_VCS][5];
  123. X    register int i, j;
  124. X    int pos, done;
  125. X                    /* doesn't exist */
  126. X    if (code[0] == -1)
  127. X        return(NO);
  128. X
  129. X    i = 0;
  130. X    j = 0;
  131. X    while (i<VCS_SIZE && j<VCS_SIZE) {
  132. X                    /* at the end (a match) */
  133. X        if (test[i] == -1 && code[j] == -1)
  134. X            return(YES);
  135. X                    /* ran out of input */
  136. X        if (test[i] == -1)
  137. X            break;
  138. X        /*
  139. X         * The char parameter (code 1000) always matches the
  140. X         * character.
  141. X         */
  142. X        if (code[j] >= 1000 && code[j] < 2000) {
  143. X            pos = code[j] -1000;
  144. X            vcs_param[k][pos] = test[i];
  145. X            i++;
  146. X            j++;
  147. X            continue;
  148. X        }
  149. X        /*
  150. X         * The digit parameter (code 2000) tries to match as many
  151. X         * ASCII digits as it can.
  152. X         */
  153. X        if (code[j] >= 2000) {
  154. X            pos = code[j] -2000;
  155. X                    /* done with this number? */
  156. X            if (vcs_param[k][pos])
  157. X                done = 1;
  158. X            else
  159. X                done = 0;
  160. X                    /* only digits */
  161. X            while (test[i] >= 48 && test[i] <= 57) {
  162. X                if (!done)
  163. X                    vcs_param[k][pos] = (vcs_param[k][pos] * 10) + test[i] -48;
  164. X                i++;
  165. X            }
  166. X                    /* ended in a digit */
  167. X            if (test[i] == -1 && code[j+1] != -1) {
  168. X                vcs_param[k][pos] = 0;
  169. X                break;
  170. X            }
  171. X            j++;
  172. X            continue;
  173. X        }
  174. X                    /* a clean miss */
  175. X        if (test[i] != code[j]) {
  176. X            for (j=0; j<5; j++)
  177. X                vcs_param[k][j] = 0;
  178. X            return(NO);
  179. X        }
  180. X        i++;
  181. X        j++;
  182. X    }
  183. X                    /* a maybe */
  184. X    return(MAYBE);
  185. X}
  186. X
  187. X/*
  188. X * Build the table of VCS codes.  Actually we cheat... We tell curses(3)
  189. X * to build the strings to perform the function, and then we decipher
  190. X * what it did.
  191. X */
  192. X
  193. Xvoid
  194. Xvcs_table()
  195. X{
  196. X    extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_opt[NUM_VCS][10];
  197. X    extern int vcs_leadin[NUM_VCS], num_leadin, max_row, max_col;
  198. X    int i, j, k, match, temp[VCS_SIZE];
  199. X    char *p, *strcpy(), buf[VCS_SIZE], *getenv(), *tparm();
  200. X    void fake_it();
  201. X
  202. X#ifdef OLDCURSES
  203. X    char tcbuf[1024], tb[1024], *t, *cursor_home, *clr_eol, *clr_eos;
  204. X    char *clear_screen, *cursor_up, *cursor_down, *cursor_right;
  205. X    char *cursor_left, *cursor_address, *getenv(), *tgetstr(), *tgoto();
  206. X
  207. X    tgetent(tb, getenv("TERM"));
  208. X    t = tcbuf;
  209. X
  210. X    cursor_home = tgetstr("ho", &t);
  211. X    clr_eol = tgetstr("ce", &t);
  212. X    clr_eos = tgetstr("cd", &t);
  213. X    clear_screen = tgetstr("cl", &t);
  214. X    cursor_up = tgetstr("up", &t);
  215. X    cursor_down = tgetstr("do", &t);
  216. X    cursor_right = tgetstr("nd", &t);
  217. X    cursor_left = tgetstr("le", &t);
  218. X    cursor_address = tgetstr("cm", &t);
  219. X    max_row = tgetnum("li");
  220. X    max_col = tgetnum("co");
  221. X#else /* OLDCURSES */
  222. X    setupterm(getenv("TERM"), 1, &i);
  223. X    max_row = lines;
  224. X    max_col = columns;
  225. X#endif /* OLDCURSES */
  226. X
  227. X    /*
  228. X     * Do the easy ones first.  These don't take positional parameters,
  229. X     * so all we have to do is strip the padding info.
  230. X     */
  231. X    for (i=0; i<NUM_VCS; i++) {
  232. X        switch (i) {
  233. X            case HOME:
  234. X                p = cursor_home;
  235. X                break;
  236. X            case CLR_EOL:
  237. X                p = clr_eol;
  238. X                break;
  239. X            case CLR_EOS:
  240. X                p = clr_eos;
  241. X                break;
  242. X            case CLEAR:
  243. X                p = clear_screen;
  244. X                break;
  245. X            case MV_UP:
  246. X                p = cursor_up;
  247. X                break;
  248. X            case MV_DOWN:
  249. X                p = cursor_down;
  250. X                break;
  251. X            case MV_RIGHT:
  252. X                p = cursor_right;
  253. X                break;
  254. X            case MV_LEFT:
  255. X                p = cursor_left;
  256. X                break;
  257. X            default:
  258. X                p = "";
  259. X                break;
  260. X        }
  261. X        /*
  262. X         * Either the capability doesn't exist, or we're gonna
  263. X         * do this one by hand (i.e.: ones with positional parameters)
  264. X         */
  265. X        if (!p) {
  266. X            vcs_codes[i][0] = -1;
  267. X            continue;
  268. X        }
  269. X                    /* fake an "output" */
  270. X        fake_it(p);
  271. X                    /* copy what it did */
  272. X        j = 0;
  273. X        while (putc_buf[j]) {
  274. X            vcs_codes[i][j] = putc_buf[j];
  275. X            j++;
  276. X            if (j == VCS_SIZE-1)
  277. X                break;
  278. X        }
  279. X        vcs_codes[i][j] = -1;
  280. X    }
  281. X
  282. X    /*
  283. X     * And now for the difficult ones.  The way it's done is: load the
  284. X     * string with a few known parameters and then find where the
  285. X     * parameters end up.  The vcs_opt[][] array is "free-flowing"
  286. X     * and means something only to the routine being used.
  287. X     */
  288. X                    /* add one to the param */
  289. X    if (substr(cursor_address, "%i") > 0)
  290. X        vcs_opt[MV_DIRECT][0] = 1;
  291. X                    /* decimal codes used */
  292. X    if (substr(cursor_address, "%d") > 0)
  293. X        vcs_opt[MV_DIRECT][1] = 1;
  294. X                    /* character codes used */
  295. X    if (substr(cursor_address, "%c") > 0)
  296. X        vcs_opt[MV_DIRECT][2] = 1;
  297. X                    /* add an offset */
  298. X    if (substr(cursor_address, "%+") > 0)
  299. X        vcs_opt[MV_DIRECT][3] = 1;
  300. X                    /* subtract an offset */
  301. X    if (substr(cursor_address, "%-") > 0)
  302. X        vcs_opt[MV_DIRECT][4] = 1;
  303. X                    /* load with parameters 12 & 34 */
  304. X#ifdef OLDCURSES
  305. X    fake_it(tgoto(cursor_address, 12, 34));
  306. X#else /* OLDCURSES */
  307. X    fake_it(tparm(cursor_address, 12, 34));
  308. X#endif /* OLDCURSES */
  309. X    j = 0;
  310. X    while (putc_buf[j]) {
  311. X        temp[j] = putc_buf[j];
  312. X        j++;
  313. X        if (j == VCS_SIZE-1)
  314. X            break;
  315. X    }
  316. X    temp[j] = -1;
  317. X                    /* if decimal parameters */
  318. X    if (vcs_opt[MV_DIRECT][1]) {
  319. X                    /* if add one */
  320. X        if (vcs_opt[MV_DIRECT][0])
  321. X            sprintf(buf, "13");
  322. X        else
  323. X            sprintf(buf, "12");
  324. X                    /* where is the 12 (or 13)? */
  325. X        if ((i = substr(putc_buf, buf)) > 0) {
  326. X            temp[i] = 2000;
  327. X            temp[i+1] = -2;
  328. X        }
  329. X        else
  330. X            temp[0] = -1;
  331. X                    /* if add one */
  332. X        if (vcs_opt[MV_DIRECT][0])
  333. X            sprintf(buf, "35");
  334. X        else
  335. X            sprintf(buf, "34");
  336. X                    /* where is the 34 (or 35)? */
  337. X        if ((i = substr(putc_buf, buf)) > 0) {
  338. X            temp[i] = 2001;
  339. X            temp[i+1] = -2;
  340. X        }
  341. X        else
  342. X            temp[0] = -1;
  343. X    }
  344. X                    /* if character parameters */
  345. X    if (vcs_opt[MV_DIRECT][2]) {
  346. X                    /* original with 12 and 34 */
  347. X        strcpy(buf, putc_buf);
  348. X                    /* change 12 to 13 */
  349. X#ifdef OLDCURSES
  350. X        fake_it(tgoto(cursor_address, 13, 34));
  351. X#else /* OLDCURSES */
  352. X        fake_it(tparm(cursor_address, 13, 34));
  353. X#endif /* OLDCURSES */
  354. X                    /* where are they different */
  355. X        i = 0;
  356. X        while (buf[i] != NULL) {
  357. X            if (buf[i] != putc_buf[i])
  358. X                break;
  359. X            i++;
  360. X        }
  361. X                    /* sanity checking */
  362. X        if (buf[i] == NULL)
  363. X            temp[0] = -1;
  364. X                    /* if add, what is offset? */
  365. X        if (vcs_opt[MV_DIRECT][3])
  366. X            vcs_opt[MV_DIRECT][5] = temp[i] - 13;
  367. X
  368. X                    /* if subtract, what is offset? */
  369. X        if (vcs_opt[MV_DIRECT][4])
  370. X            vcs_opt[MV_DIRECT][5] = 13 - temp[i];
  371. X
  372. X        temp[i] = 1000;
  373. X                    /* change 34 to 35 */
  374. X#ifdef OLDCURSES
  375. X        fake_it(tgoto(cursor_address, 12, 35));
  376. X#else /* OLDCURSES */
  377. X        fake_it(tparm(cursor_address, 12, 35));
  378. X#endif /* OLDCURSES */
  379. X                    /* where are they different */
  380. X        i = 0;
  381. X        while (buf[i] != NULL) {
  382. X            if (buf[i] != putc_buf[i])
  383. X                break;
  384. X            i++;
  385. X        }
  386. X        temp[i] = 1001;
  387. X        if (buf[i] == NULL)
  388. X            temp[0] = -1;
  389. X    }
  390. X                    /* strip the -2's out, if any */
  391. X    i = 0;
  392. X    j = 0;
  393. X    while (temp[i] != -1) {
  394. X        if (temp[i] != -2)
  395. X            vcs_codes[MV_DIRECT][j++] = temp[i];
  396. X        i++;
  397. X    }
  398. X    vcs_codes[MV_DIRECT][j] = -1;
  399. X
  400. X    /*
  401. X     * Simplify the list.  Some codes are already handled by the
  402. X     * virtual screen routines... no need to duplicate them.
  403. X     */
  404. X    if (vcs_codes[MV_DOWN][0] == '\n')
  405. X        vcs_codes[MV_DOWN][0] = -1;
  406. X
  407. X    if (vcs_codes[MV_LEFT][0] == 8)
  408. X        vcs_codes[MV_LEFT][0] = -1;
  409. X
  410. X    /*
  411. X     * Often the "clear screen" sequence will contain the "home"
  412. X     * sequence... if so, don't duplicate the "home" portion.
  413. X     */
  414. X    fake_it(cursor_home);
  415. X    strcpy(buf, putc_buf);
  416. X
  417. X    fake_it(clear_screen);
  418. X                    /* if "home" inside "clear screen" */
  419. X    if ((k = substr(putc_buf, buf)) >= 0) {
  420. X                    /* if at the beginning */
  421. X        if (k == 0) {
  422. X            i = 0;
  423. X            for (j=strlen(buf); j<VCS_SIZE; j++)
  424. X                vcs_codes[CLEAR][i++] = putc_buf[j];
  425. X            vcs_codes[CLEAR][i] = -1;
  426. X        }
  427. X                    /* if at the end */
  428. X        else if (strlen(buf)+k == strlen(putc_buf))
  429. X            vcs_codes[CLEAR][k] = -1;
  430. X    }
  431. X                    /* is "clear screen" still unique */
  432. X    k = 0;
  433. X    for (i=0; i<NUM_VCS; i++) {
  434. X        if (vcs_codes[CLEAR][i] == -1 || vcs_codes[CLR_EOS][i] == -1)
  435. X            break;
  436. X        if (vcs_codes[CLEAR][i] != vcs_codes[CLR_EOS][i]) {
  437. X            k++;
  438. X            break;
  439. X        }
  440. X    }
  441. X    if (k == 0)
  442. X        vcs_codes[CLEAR][0] = -1;
  443. X
  444. X    /*
  445. X     * Make a list of unique lead-in characters to be used as a
  446. X     * simple hash table.
  447. X     */
  448. X    num_leadin = 0;
  449. X    for (i=0; i<NUM_VCS; i++) {
  450. X        if (vcs_codes[i][0] == -1)
  451. X            continue;
  452. X                    /* add any new lead-in character */
  453. X        match = 0;
  454. X        for (j=0; j<num_leadin; j++) {
  455. X            if (vcs_leadin[j] == vcs_codes[i][0])
  456. X                match++;
  457. X        }
  458. X        if (!match)
  459. X            vcs_leadin[num_leadin++] = vcs_codes[i][0];
  460. X    }
  461. X    return;
  462. X}
  463. X
  464. X/*
  465. X * The routines that fakes curses(3) into outputing the string info with
  466. X * the padding removed.
  467. X */
  468. Xstatic void
  469. Xfake_it(s)
  470. Xchar *s;
  471. X{
  472. X    int fake_putc();
  473. X
  474. X    putc_cnt = 0;
  475. X    putc_buf[0] = NULL;
  476. X    tputs(s, 1, fake_putc);
  477. X    putc_buf[putc_cnt] = NULL;
  478. X    return;
  479. X}
  480. Xstatic int
  481. Xfake_putc(c)
  482. Xchar c;
  483. X{
  484. X    putc_buf[putc_cnt++] = c;
  485. X    return(c);
  486. X}
  487. X
  488. X/*
  489. X * Is string2 contained in string1?  If so, return the offset otherwise
  490. X * return a -1.
  491. X */
  492. X
  493. Xstatic int
  494. Xsubstr(s1, s2)
  495. Xchar *s1, *s2;
  496. X{
  497. X    int i, len;
  498. X
  499. X    len = strlen(s2);
  500. X                    /* not possible */
  501. X    if (len > strlen(s1))
  502. X        return(-1);
  503. X
  504. X    i = 0;
  505. X    while (*s1) {
  506. X        if (!strncmp(s1, s2, len))
  507. X            return(i);
  508. X        s1++;
  509. X        i++;
  510. X    }
  511. X    return(-1);
  512. X}
  513. SHAR_EOF
  514. if test 10169 -ne "`wc -c < 'vcs.c'`"
  515. then
  516.     echo shar: "error transmitting 'vcs.c'" '(should have been 10169 characters)'
  517. fi
  518. fi
  519. echo shar: "extracting 'x_ascii.c'" '(7019 characters)'
  520. if test -f 'x_ascii.c'
  521. then
  522.     echo shar: "will not over-write existing file 'x_ascii.c'"
  523. else
  524. sed 's/^X//' << \SHAR_EOF > 'x_ascii.c'
  525. X/*
  526. X * Transfer a file using just XON/XOFF flow control.  Currently limited to
  527. X * 7 bit ASCII codes.  (If this causes too much trouble, I'll change it).
  528. X */
  529. X
  530. X#define CLIST    64
  531. X
  532. X#include <stdio.h>
  533. X#include <fcntl.h>
  534. X#include <curses.h>
  535. X#include <signal.h>
  536. X#include "config.h"
  537. X#include "misc.h"
  538. X#include "param.h"
  539. X
  540. Xvoid
  541. Xxfer_ascii(list, up)
  542. Xchar *list;
  543. Xint up;
  544. X{
  545. X    int cr_lf;
  546. X    char *file, *strtok();
  547. X    void send_ascii(), rcv_ascii(), line_set(), st_line(), suspend();
  548. X    void load_vs(), ascii_mode();
  549. X    unsigned int sleep();
  550. X
  551. X    touchwin(stdscr);
  552. X    refresh();
  553. X                    /* only one file from list */
  554. X    file = strtok(list, "     ");
  555. X
  556. X    cr_lf = !strcmp(param->cr_out, "CR/LF");
  557. X    ascii_mode(up);
  558. X    if (up) {
  559. X                    /* un-suspend the input routine */
  560. X        suspend(0);
  561. X
  562. X        send_ascii(file, cr_lf);
  563. X                    /* re-suspend the input routine */
  564. X        suspend(1);
  565. X    }
  566. X    else
  567. X        rcv_ascii(file, cr_lf);
  568. X
  569. X    /*
  570. X     * Restoring the TTY modes is easier than setting them... The
  571. X     * fixterm() and line_set() routines fix most of the damage.
  572. X     */
  573. X    fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NDELAY);
  574. X    line_set();
  575. X    fixterm();
  576. X
  577. X    /*
  578. X     * On downloading, the contents of the virtual screen won't contain
  579. X     * the characters shown during the transfer.  Too bad...
  580. X     */
  581. X    load_vs();
  582. X    beep();
  583. X    st_line("xfer complete");
  584. X
  585. X    sleep(2);
  586. X    return;
  587. X}
  588. X
  589. X/*
  590. X * Put the TTY line in a mode suitable for the ASCII transfer.  Puts the
  591. X * terminal in the raw, non-blocking mode.
  592. X */
  593. X
  594. Xstatic void
  595. Xascii_mode(up)
  596. Xint up;
  597. X{
  598. X    extern int fd;
  599. X    struct termio tbuf;
  600. X    void input_off(), term_mode();
  601. X
  602. X    ioctl(fd, TCGETA, &tbuf);
  603. X    tbuf.c_oflag = 0;
  604. X                    /* flow control & 8th bit stripping */
  605. X    if (up) {
  606. X        tbuf.c_iflag = (ISTRIP|IXON);
  607. X
  608. X                    /* use NL delays if no CR */
  609. X        if (!strcmp(param->cr_up, "STRIP"))
  610. X            tbuf.c_oflag = (OPOST|ONLRET);
  611. X
  612. X                    /* CR delay times */
  613. X        switch (param->cr_delay) {
  614. X            case 0:
  615. X                tbuf.c_oflag = 0;
  616. X                break;
  617. X            case 100:
  618. X                tbuf.c_oflag |= (OPOST|CR2);
  619. X                break;
  620. X            case 150:
  621. X                tbuf.c_oflag |= (OPOST|CR3);
  622. X                break;
  623. X        }
  624. X    }
  625. X                    /* if down loading */
  626. X    else {
  627. X        tbuf.c_iflag = (ISTRIP|IXOFF);
  628. X                    /* kill the input routine */
  629. X        input_off();
  630. X    }
  631. X
  632. X    ioctl(fd, TCSETA, &tbuf);
  633. X    ioctl(fd, TCFLSH, 2);
  634. X                    /* out of curses mode */
  635. X    resetterm();
  636. X    term_mode();
  637. X                    /* non-blocking mode */
  638. X    fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) | O_NDELAY);
  639. X    return;
  640. X}
  641. X
  642. X/*
  643. X * Send a file.  The local echo option is independent of the duplex option,
  644. X * and would very rarely be used since the characters are most likely
  645. X * being echoed on the screen anyway.
  646. X */
  647. X
  648. Xstatic void
  649. Xsend_ascii(file, cr_lf)
  650. Xchar *file;
  651. Xint cr_lf;
  652. X{
  653. X    extern int fd;
  654. X    FILE *fp;
  655. X    int i, j, strip_cr, strip_lf, add_cr, add_lf, expand, lecho, pace;
  656. X    unsigned char c, last;
  657. X    unsigned int sleep();
  658. X                    /* permission already checked */
  659. X    if (!(fp = fopen(file, "r")))
  660. X        return;
  661. X                    /* ASCII transfer options */
  662. X    strip_cr = !strcmp(param->cr_up, "STRIP");
  663. X    add_lf = !strcmp(param->cr_up, "ADD LF");
  664. X    strip_lf = !strcmp(param->lf_up, "STRIP");
  665. X    add_cr = !strcmp(param->lf_up, "ADD CR");
  666. X    expand = !strcmp(param->expand, "YES");
  667. X    lecho = !strcmp(param->lecho, "YES");
  668. X    pace = !strcmp(param->pace, "YES");
  669. X
  670. X    last = 0;
  671. X    while ((i = fgetc(fp)) != EOF) {
  672. X                    /* any keyboard activity? */
  673. X        switch (j = getchar()) {
  674. X            case -1:    /* no key was pressed */
  675. X                break;
  676. X            case ESC:    /* <ESC> key for abort */
  677. X                fclose(fp);
  678. X                sleep(2);
  679. X                ioctl(fd, TCSBRK, 1);
  680. X                return;
  681. X            default:    /* send the char */
  682. X                c = j & 0xff;
  683. X                putc_line(c);
  684. X                if (c == '\r' && cr_lf)
  685. X                    putc_line('\n');
  686. X                break;
  687. X        }
  688. X        c = i & 0xff;
  689. X                    /* expand blank lines */
  690. X        if (expand && last == '\n' && c == '\n')
  691. X            putc_line(' ');
  692. X        last = c;
  693. X
  694. X                    /* CR translations */
  695. X        if (c == '\r' && strip_cr)
  696. X            continue;
  697. X        if (c == '\r' && add_lf) {
  698. X            putc_line(c);
  699. X            putc_line('\n');
  700. X            continue;
  701. X        }
  702. X                    /* LF translations */
  703. X        if (c == '\n' && strip_lf)
  704. X            continue;
  705. X        if (c == '\n' && add_cr) {
  706. X            putc_line('\r');
  707. X            putc_line(c);
  708. X            continue;
  709. X        }
  710. X        putc_line(c);
  711. X        /*
  712. X         * There's really no mechanism for delaying characters
  713. X         * going to the output, so we fake it by waiting for
  714. X         * each character to clear the I/O buffer.
  715. X         */
  716. X        if (pace)
  717. X            ioctl(fd, TCSBRK, 1);
  718. X        if (lecho) {
  719. X            putchar((char) c);
  720. X            fflush(stdout);
  721. X        }
  722. X    }
  723. X    fclose(fp);
  724. X    sleep(2);
  725. X    ioctl(fd, TCSBRK, 1);
  726. X    return;
  727. X}
  728. X
  729. X/*
  730. X * Receive a file.  The timer is used to end the transfer.  This is not
  731. X * that much different from the data logging option.  The use of bgetc_line()
  732. X * and non-blocking input makes it seem like full duplex, but it's not.
  733. X * Be aware that while the timer is active the keyboard is deaf.  Input is
  734. X * NOT loaded into the virtual screen!!
  735. X */
  736. X
  737. Xstatic void
  738. Xrcv_ascii(file, cr_lf)
  739. Xchar *file;
  740. Xint cr_lf;
  741. X{
  742. X    FILE *fp;
  743. X    int i, strip_cr, strip_lf, add_cr, add_lf, got_first;
  744. X    unsigned int delay;
  745. X    char c;
  746. X                    /* permission already checked */
  747. X    if (!(fp = fopen(file, "w")))
  748. X        return;
  749. X                    /* ASCII transfer options */
  750. X    strip_cr = !strcmp(param->cr_dn, "STRIP");
  751. X    add_lf = !strcmp(param->cr_dn, "ADD LF");
  752. X    strip_lf = !strcmp(param->lf_dn, "STRIP");
  753. X    add_cr = !strcmp(param->lf_dn, "ADD CR");
  754. X
  755. X    got_first = 0;
  756. X    delay = 1;
  757. X    while (1) {
  758. X                    /* keyboard activity */
  759. X        switch (i = getchar()) {
  760. X            case -1:    /* no key was pressed */
  761. X                break;
  762. X            case ESC:    /* <ESC> key */
  763. X                fclose(fp);
  764. X                return;
  765. X            default:    /* send it */
  766. X                c = i & 0xff;
  767. X                putc_line((unsigned char) c);
  768. X                if (c == '\r' && cr_lf)
  769. X                    putc_line('\n');
  770. X                break;
  771. X        }
  772. X                    /* read a character */
  773. X        if ((i = bgetc_line(delay)) == -1) {
  774. X            /*
  775. X             * The transfer timeout is not activated until the
  776. X             * first character is received.  Until then, it polls
  777. X             * the line for one second and loops backs for
  778. X             * keyboard input.
  779. X             */
  780. X            if (got_first) {
  781. X                fclose(fp);
  782. X                return;
  783. X            }
  784. X            continue;
  785. X        }
  786. X        got_first = 1;
  787. X        delay = param->timer;
  788. X        c = i & 0xff;
  789. X                    /* display it on the screen */
  790. X        putchar(c);
  791. X        fflush(stdout);
  792. X                    /* CR translations */
  793. X        if (c == '\r' && strip_cr)
  794. X            continue;
  795. X        if (c == '\r' && add_lf) {
  796. X            fputc(c, fp);
  797. X            fputc('\n', fp);
  798. X            continue;
  799. X        }
  800. X                    /* LF translations */
  801. X        if (c == '\n' && strip_lf)
  802. X            continue;
  803. X        if (c == '\n' && add_cr) {
  804. X            fputc('\r', fp);
  805. X            fputc(c, fp);
  806. X            continue;
  807. X        }
  808. X        fputc(c, fp);
  809. X    }
  810. X}
  811. X
  812. X/*
  813. X * Get a character from the line (using buffered I/O) with a specified
  814. X * time-out period in seconds.  If the function times-out, it returns a -1.
  815. X */
  816. X
  817. Xstatic int bl_flag;
  818. X
  819. Xstatic int
  820. Xbgetc_line(sec)
  821. Xunsigned int sec;
  822. X{
  823. X    int bl_force();
  824. X    char c;
  825. X    unsigned int alarm();
  826. X
  827. X    signal(SIGALRM, bl_force);
  828. X    bl_flag = 0;
  829. X
  830. X    alarm(sec);
  831. X    if ((int) (c = buf_read()) < 0) {
  832. X        alarm(0);
  833. X        return(-1);
  834. X    }
  835. X    if (bl_flag)
  836. X        return(-1);
  837. X    alarm(0);
  838. X    return(c & 0xff);
  839. X}
  840. X/*ARGSUSED*/
  841. Xstatic int
  842. Xbl_force(dummy)
  843. Xint dummy;
  844. X{
  845. X    bl_flag = 1;
  846. X}
  847. X
  848. X/*
  849. X * Do a single character buffered read from the serial port.
  850. X */
  851. X
  852. Xstatic int
  853. Xbuf_read()
  854. X{
  855. X    extern int fd;
  856. X    static char buf[CLIST];
  857. X    static char *bufp = buf;
  858. X    static int n = 0;
  859. X
  860. X    if (n <= 0) {
  861. X        if ((n = read(fd, buf, CLIST)) <= 0)
  862. X            return(-1);
  863. X        bufp = buf;
  864. X    }
  865. X    while (--n >= 0)
  866. X        return(*bufp++ & 0xff);
  867. X    return(-1);
  868. X}
  869. SHAR_EOF
  870. if test 7019 -ne "`wc -c < 'x_ascii.c'`"
  871. then
  872.     echo shar: "error transmitting 'x_ascii.c'" '(should have been 7019 characters)'
  873. fi
  874. fi
  875. echo shar: "extracting 'x_batch.c'" '(8478 characters)'
  876. if test -f 'x_batch.c'
  877. then
  878.     echo shar: "will not over-write existing file 'x_batch.c'"
  879. else
  880. sed 's/^X//' << \SHAR_EOF > 'x_batch.c'
  881. X/*
  882. X * Routines to support the batch protocols.
  883. X */
  884. X
  885. X#include <stdio.h>
  886. X#include <ctype.h>
  887. X#include <curses.h>
  888. X#include "config.h"
  889. X#include "misc.h"
  890. X#include "xmodem.h"
  891. X
  892. X/*
  893. X * Send the file name for the modem7 batch.  Only uses 11 characters
  894. X * of the filename.
  895. X */
  896. X
  897. Xint
  898. Xsend_modem7(win, name)
  899. XWINDOW *win;
  900. Xchar *name;
  901. X{
  902. X    char *new_name, *fix_name();
  903. X    unsigned char sum, calc_sum();
  904. X
  905. X                    /* convert to 11 character name */
  906. X    new_name = fix_name(name);
  907. X    sum = calc_sum((unsigned char *) new_name, 12);
  908. X
  909. X    putc_line(ACK);
  910. X                    /* for each character in the name */
  911. X    while (*new_name != CTRLZ) {
  912. X        putc_line((unsigned char) *new_name);
  913. X
  914. X        switch (getc_line(3)) {
  915. X            case -1:    /* timed out */
  916. X                clear_line(win, 12, 24, 1);
  917. X                waddstr(win, "NO RESPONSE");
  918. X                wrefresh(win);
  919. X                return(ERROR);
  920. X            case ACK:    /* got it! */
  921. X                break;
  922. X            case CAN:    /* cancel transmission */
  923. X                if (getc_line(2) == CAN) {
  924. X                    beep();
  925. X                    clear_line(win, 12, 24, 1);
  926. X                    wattrstr(win, A_BOLD, "REMOTE ABORTED");
  927. X                    wrefresh(win);
  928. X                    return(CANCEL);
  929. X                }
  930. X                /* fall thru... */
  931. X            default:
  932. X                clear_line(win, 12, 24, 1);
  933. X                waddstr(win, "NAME FAILED");
  934. X                wrefresh(win);
  935. X                return(ERROR);
  936. X        }
  937. X        new_name++;
  938. X    }
  939. X    putc_line(CTRLZ);
  940. X                    /* verify the checksum */
  941. X    if (getc_line(10) != sum) {
  942. X        putc_line('u');
  943. X        clear_line(win, 12, 24, 1);
  944. X        waddstr(win, "CHECKSUM FAILED");
  945. X        wrefresh(win);
  946. X        return(ERROR);
  947. X    }
  948. X    putc_line(ACK);
  949. X    return(0);
  950. X}
  951. X
  952. X/*
  953. X * Receive a modem7 file name.  A return code of 1 means the end of the
  954. X * batch transfers.
  955. X */
  956. X
  957. Xint
  958. Xrcv_modem7(win, default_err)
  959. XWINDOW *win;
  960. Xint default_err;
  961. X{
  962. X    extern char file_name[15];
  963. X    int i, j, err_method, err_count, got_it;
  964. X    unsigned char sum, calc_sum();
  965. X    char temp_name[13];
  966. X    void change_name(), unfix_name();
  967. X
  968. X    err_method = default_err;
  969. X    if (default_err == CRC_CHECKSUM)
  970. X        err_method = CRC;
  971. X
  972. X    err_count = 0;
  973. X    got_it = 0;
  974. X    while (err_count < MAX_ERRORS) {
  975. X                    /* switch to checksum? */
  976. X        if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
  977. X            err_method = CHECKSUM;
  978. X
  979. X        if (err_method == CRC)
  980. X            putc_line('C');
  981. X        else
  982. X            putc_line(NAK);
  983. X                    /* what'd we get? */
  984. X        switch (getc_line(10)) {
  985. X            case -1:    /* timed out */
  986. X                clear_line(win, 12, 24, 1);
  987. X                wattrstr(win, A_BOLD, "NO RESPONSE");
  988. X                wrefresh(win);
  989. X                err_count++;
  990. X            case ACK:    /* ready to go... */
  991. X                got_it++;
  992. X                break;
  993. X            default:    /* huh? */
  994. X                clear_line(win, 12, 24, 1);
  995. X                wattrstr(win, A_BOLD, "BAD HEADER");
  996. X                wrefresh(win);
  997. X                err_count++;
  998. X        }
  999. X    }
  1000. X    if (!got_it)
  1001. X        return(ERROR);
  1002. X                    /* get the name */
  1003. X    for (i=0; i<12; i++) {
  1004. X        j = getc_line(3);
  1005. X
  1006. X        switch (j) {
  1007. X            case -1:    /* timed out */
  1008. X                clear_line(win, 12, 24, 1);
  1009. X                wattrstr(win, A_BOLD, "NO RESPONSE");
  1010. X                wrefresh(win);
  1011. X                return(ERROR);
  1012. X            case EOT:    /* end of batch? */
  1013. X                return(-1);
  1014. X            case CAN:    /* cancel transmission */
  1015. X                if (getc_line(2) == CAN) {
  1016. X                    beep();
  1017. X                    clear_line(win, 12, 24, 1);
  1018. X                    wattrstr(win, A_BOLD, "REMOTE ABORTED");
  1019. X                    wrefresh(win);
  1020. X                    return(CANCEL);
  1021. X                }
  1022. X                /* fall thru... */
  1023. X            case 'u':    /* bad name character */
  1024. X                beep();
  1025. X                clear_line(win, 12, 24, 1);
  1026. X                wattrstr(win, A_BOLD, "BAD NAME");
  1027. X                wrefresh(win);
  1028. X                return(ERROR);
  1029. X            default:    /* the name... */
  1030. X                temp_name[i] = j & 0xff;
  1031. X                if (j != CTRLZ)
  1032. X                    putc_line(ACK);
  1033. X                break;
  1034. X        }
  1035. X    }
  1036. X    temp_name[12] = NULL;
  1037. X                    /* send our checksum */
  1038. X    sum = calc_sum((unsigned char *) temp_name, 12);
  1039. X    putc_line(sum);
  1040. X                    /* do they agree? */
  1041. X    if (getc_line(10) != ACK) {
  1042. X        beep();
  1043. X        clear_line(win, 12, 24, 1);
  1044. X        wattrstr(win, A_BOLD, "BAD NAME");
  1045. X        wrefresh(win);
  1046. X        return(ERROR);
  1047. X    }
  1048. X                    /* load the file_name array */
  1049. X    unfix_name(temp_name);
  1050. X                    /* any name collisions? */
  1051. X    change_name(win, file_name);
  1052. X    return(0);
  1053. X}
  1054. X
  1055. X/*
  1056. X * Send the block 0 information for a ymodem batch transfer.  Uses only
  1057. X * the name component of the path and the file size.
  1058. X */
  1059. X
  1060. Xint
  1061. Xsend_ymodem(win, file, size)
  1062. XWINDOW *win;
  1063. Xchar *file;
  1064. Xlong size;
  1065. X{
  1066. X    register int i;
  1067. X    unsigned short crc, calc_crc();
  1068. X    char *strcpy();
  1069. X    unsigned char buf[133];
  1070. X                    /* start with a clean block */
  1071. X    for (i=0; i<132; i++)
  1072. X        buf[i] = NULL;
  1073. X                    /* the header */
  1074. X    buf[0] = SOH;
  1075. X    buf[1] = 0;
  1076. X    buf[2] = 255;
  1077. X
  1078. X    /*
  1079. X     * The block zero consists of the file name (no path component),
  1080. X     * a NULL, and the file length (as a string).  The end of batch
  1081. X     * marker is an empty block.
  1082. X     */
  1083. X    if (*file != NULL) {
  1084. X        strcpy((char *) &buf[3], file);
  1085. X        sprintf((char *) &buf[strlen(file)+4], "%ld", size);
  1086. X    }
  1087. X                    /* the crc */
  1088. X    crc = calc_crc(&buf[3], 128);
  1089. X    buf[131] = crc >> 8;
  1090. X    buf[132] = crc;
  1091. X                    /* the block count */
  1092. X    mvwaddstr(win, 7, 24, "0   ");
  1093. X
  1094. X    return(send_block(win, buf, 133));
  1095. X}
  1096. X
  1097. X/*
  1098. X * Receive the block 0 information for a ymodem batch transfer.  We
  1099. X * only use the file name and the size (if present).  Currently doesn't
  1100. X * support full path names.
  1101. X */
  1102. X
  1103. Xint
  1104. Xrcv_ymodem(win)
  1105. XWINDOW *win;
  1106. X{
  1107. X    extern unsigned char buf[1029];
  1108. X    extern long file_length;
  1109. X    extern char file_name[15];
  1110. X    int code, length_is_at;
  1111. X    long atol();
  1112. X
  1113. X    file_length = 0L;
  1114. X    file_name[0] = NULL;
  1115. X                    /* read the zero block */
  1116. X    if (code = rcv_block(win, 1, 1024, 0))
  1117. X        return(code);
  1118. X                    /* at end of batch */
  1119. X    if (buf[3] == NULL)
  1120. X        return(0);
  1121. X                    /* get the file name */
  1122. X    change_name(win, (char *) &buf[3]);
  1123. X                    /* any trouble? */
  1124. X    if (file_name[0] == NULL) {
  1125. X        putc_line(CAN);
  1126. X        return(0);
  1127. X    }
  1128. X    /*
  1129. X     * The file length is placed after the NULL of the file name
  1130. X     * and is terminated by another NULL.  If the length is missing,
  1131. X     * atol() will see a NULL and return 0.
  1132. X     */
  1133. X    length_is_at = strlen((char *) &buf[3]) + 4;
  1134. X    file_length = atol((char *) &buf[length_is_at]);
  1135. X    return(0);
  1136. X}
  1137. X
  1138. X/*
  1139. X * Handle file name collisions.  Prepend an "X" to the name until you find
  1140. X * a name that doesn't already exist.  Creates a NULL name on error.
  1141. X * Loads the global character array "file_name".
  1142. X */
  1143. X
  1144. Xvoid
  1145. Xchange_name(win, str)
  1146. XWINDOW *win;
  1147. Xchar *str;
  1148. X{
  1149. X    extern char file_name[15];
  1150. X    register int i;
  1151. X    int modified;
  1152. X    char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
  1153. X    unsigned int sleep();
  1154. X                    /* dissect the name component */
  1155. X    if ((s = strrchr(str, '/')))
  1156. X        strcpy(temp, s++);
  1157. X    else
  1158. X        strcpy(temp, str);
  1159. X
  1160. X    strcpy(ans, temp);
  1161. X    file_name[0] = NULL;
  1162. X                    /* write permission on directory? */
  1163. X    if (access(".", 2)) {
  1164. X        beep();
  1165. X        clear_line(win, 12, 24, 1);
  1166. X        wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY");
  1167. X        wrefresh(win);
  1168. X        return;
  1169. X    }
  1170. X                    /* prepend up to 13 "X"s */
  1171. X    modified = 0;
  1172. X    for (i=1; i<14; i++) {
  1173. X        if (access(ans, 0)) {
  1174. X            if (modified) {
  1175. X                beep();
  1176. X                clear_line(win, 12, 24, 1);
  1177. X                waddstr(win, "NAME COLLISION");
  1178. X                wrefresh(win);
  1179. X                sleep(1);
  1180. X            }
  1181. X            strcpy(file_name, ans);
  1182. X            return;
  1183. X        }
  1184. X
  1185. X        modified++;
  1186. X        strcpy(temp, "X");
  1187. X        strncat(temp, ans, 13);
  1188. X        temp[14] = NULL;
  1189. X        strcpy(ans, temp);
  1190. X    }
  1191. X    beep();
  1192. X    clear_line(win, 12, 24, 1);
  1193. X    waddstr(win, "BAD NAME");
  1194. X    wrefresh(win);
  1195. X    return;
  1196. X}
  1197. X
  1198. X/*
  1199. X * Convert a perfectly good Unix file name to fit the CP/M file name
  1200. X * rules.  Used for the modem7 batch file transfer.  Returns a pointer
  1201. X * to the new name.
  1202. X */
  1203. X
  1204. Xchar *
  1205. Xfix_name(path)
  1206. Xchar *path;
  1207. X{
  1208. X    int dot;
  1209. X    char *s, *name, temp[15], *ext, *strcpy(), *strrchr();
  1210. X    static char ans[13];
  1211. X                    /* ignore the path component */
  1212. X    if (s = strrchr(path, '/'))
  1213. X        strcpy(temp, s++);
  1214. X    else
  1215. X        strcpy(temp, path);
  1216. X    name = temp;
  1217. X
  1218. X    ext = NULL;
  1219. X    dot = 0;
  1220. X    for (s=name; *s; ++s) {
  1221. X        if (*s == '.' && !dot) {
  1222. X            dot++;
  1223. X            *s = NULL;
  1224. X            ext = s + 1;
  1225. X        }
  1226. X        if (islower(*s))
  1227. X            *s = toupper(*s);
  1228. X    }
  1229. X                    /* if null name component */
  1230. X    if (*name == NULL)
  1231. X        name = "X";
  1232. X                    /* if name too long */
  1233. X    if (strlen(name) > 8)
  1234. X        *(name+8) = NULL;
  1235. X                    /* if extension too long */
  1236. X    if (strlen(ext) > 3)
  1237. X        *(ext+3) = NULL;
  1238. X
  1239. X    sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ);
  1240. X    return(ans);
  1241. X}
  1242. X
  1243. X/*
  1244. X * Convert a CP/M style filename into a legal Unix file name.  Loads the
  1245. X * global character array "file_name".
  1246. X */
  1247. X
  1248. Xvoid
  1249. Xunfix_name(cpm_name)
  1250. Xchar *cpm_name;
  1251. X{
  1252. X    extern char file_name[15];
  1253. X    register int i, n;
  1254. X    int dot;
  1255. X    char temp[15];
  1256. X
  1257. X    file_name[0] = NULL;
  1258. X    if (!*cpm_name)
  1259. X        return;
  1260. X
  1261. X    strcpy(temp, cpm_name);
  1262. X                    /* 8 character of the name */
  1263. X    n = 0;
  1264. X    for (i=0; i<8; i++) {
  1265. X        if (temp[i] != ' ') {
  1266. X            if (isupper(temp[i]))
  1267. X                file_name[n++] = tolower(temp[i]);
  1268. X            else
  1269. X                file_name[n++] = temp[i];
  1270. X        }
  1271. X    }
  1272. X                    /* 3 character extension */
  1273. X    dot = 0;
  1274. X    for (i=8; i<11; i++) {
  1275. X        if (temp[i] != ' ') {
  1276. X            if (!dot) {
  1277. X                dot++;
  1278. X                file_name[n++] = '.';
  1279. X            }
  1280. X            if (isupper(temp[i]))
  1281. X                file_name[n++] = tolower(temp[i]);
  1282. X            else
  1283. X                file_name[n++] = temp[i];
  1284. X        }
  1285. X    }
  1286. X    file_name[n] = NULL;
  1287. X    return;
  1288. X}
  1289. SHAR_EOF
  1290. if test 8478 -ne "`wc -c < 'x_batch.c'`"
  1291. then
  1292.     echo shar: "error transmitting 'x_batch.c'" '(should have been 8478 characters)'
  1293. fi
  1294. fi
  1295. echo shar: "extracting 'x_extrnl.c'" '(1569 characters)'
  1296. if test -f 'x_extrnl.c'
  1297. then
  1298.     echo shar: "will not over-write existing file 'x_extrnl.c'"
  1299. else
  1300. sed 's/^X//' << \SHAR_EOF > 'x_extrnl.c'
  1301. X/*
  1302. X * Spawn a shell with the stdin and stdout swapped with the remote
  1303. X * system.  An undocumented feature:  The external protocol gateway
  1304. X * can be used to pipe the output of a normal Unix command to the
  1305. X * remote system.
  1306. X */
  1307. X
  1308. X#include <stdio.h>
  1309. X#include <signal.h>
  1310. X#include <curses.h>
  1311. X#include <fcntl.h>
  1312. X#include "config.h"
  1313. X
  1314. Xvoid
  1315. Xextrnl(cmd)
  1316. Xchar *cmd;
  1317. X{
  1318. X    extern int fd;
  1319. X    WINDOW *xt_win, *newwin();
  1320. X    int (*istat)(), (*qstat)(), status, epid, w;
  1321. X    char *shell, *shellpath, *getenv(), *strrchr(), buf[40], *ttyname();
  1322. X    char *strcpy();
  1323. X    unsigned int sleep();
  1324. X    void _exit(), input_off();
  1325. X
  1326. X    input_off();
  1327. X                    /* a full window */
  1328. X    xt_win = newwin(LINES, COLS, 0, 0);
  1329. X    touchwin(xt_win);
  1330. X    wrefresh(xt_win);
  1331. X                    /* out of curses mode */
  1332. X    resetterm();
  1333. X
  1334. X    shellpath = getenv("SHELL");
  1335. X    if (shellpath == NULL || *shellpath == NULL)
  1336. X        shellpath = "/bin/sh";
  1337. X
  1338. X    shell = strrchr(shellpath, '/') + 1;
  1339. X
  1340. X    if (!(epid = fork())) {
  1341. X                        /* recreate the device name */
  1342. X        strcpy(buf, ttyname(fd));
  1343. X        close(fd);
  1344. X                        /* swap the stdin */
  1345. X        close(0);
  1346. X        open(buf, O_RDONLY);
  1347. X                        /* swap the stdout */
  1348. X        close(1);
  1349. X        open(buf, O_WRONLY);
  1350. X#ifdef SETUGID
  1351. X        setgid(getgid());
  1352. X        setuid(getuid());
  1353. X#endif /* SETUGID */
  1354. X        execl(shellpath, shell, "-c", cmd, (char *) 0);
  1355. X        _exit(1);
  1356. X    }
  1357. X    istat = signal(SIGINT, SIG_IGN);
  1358. X    qstat = signal(SIGQUIT, SIG_IGN);
  1359. X
  1360. X    while ((w = wait(&status)) != epid && w != -1)
  1361. X        ;
  1362. X
  1363. X    signal(SIGINT, istat);
  1364. X    signal(SIGQUIT, qstat);
  1365. X                    /* back to curses mode */
  1366. X    sleep(1);
  1367. X    fixterm();
  1368. X
  1369. X    clearok(curscr, TRUE);
  1370. X    werase(xt_win);
  1371. X    wrefresh(xt_win);
  1372. X    delwin(xt_win);
  1373. X    return;
  1374. X}
  1375. SHAR_EOF
  1376. if test 1569 -ne "`wc -c < 'x_extrnl.c'`"
  1377. then
  1378.     echo shar: "error transmitting 'x_extrnl.c'" '(should have been 1569 characters)'
  1379. fi
  1380. fi
  1381. echo shar: "extracting 'x_menu.c'" '(5812 characters)'
  1382. if test -f 'x_menu.c'
  1383. then
  1384.     echo shar: "will not over-write existing file 'x_menu.c'"
  1385. else
  1386. sed 's/^X//' << \SHAR_EOF > 'x_menu.c'
  1387. X/*
  1388. X * Open a window to display the choices of file transfer protocols and
  1389. X * prompt for the file name(s).  A return code of 1 means turn the
  1390. X * input routine back on.
  1391. X */
  1392. X
  1393. X#include <stdio.h>
  1394. X#include <sys/types.h>
  1395. X#include <sys/stat.h>
  1396. X#include <curses.h>
  1397. X#include "config.h"
  1398. X#include "misc.h"
  1399. X#include "xmodem.h"
  1400. X
  1401. Xint
  1402. Xxfer_menu(up)
  1403. Xint up;
  1404. X{
  1405. X    extern int fd;
  1406. X    extern char *null_ptr;
  1407. X    WINDOW *xm_win, *newwin();
  1408. X    char *list, *get_names(), *get_extrnl();
  1409. X    int type, is_batch;
  1410. X    void xfer_win(), xfer_ascii(), free_ptr(), extrnl(), error_win();
  1411. X
  1412. X    xm_win = newwin(15, 20, 2, 45);
  1413. X
  1414. X    mvwaddstr(xm_win, 2, 3, "1) xmodem");
  1415. X    mvwaddstr(xm_win, 3, 3, "2) xmodem-1k");
  1416. X    mvwaddstr(xm_win, 4, 3, "3) modem7");
  1417. X    mvwaddstr(xm_win, 5, 3, "4) ymodem");
  1418. X    mvwaddstr(xm_win, 6, 3, "5) ymodem-g");
  1419. X    mvwaddstr(xm_win, 7, 3, "6) ASCII");
  1420. X    mvwaddstr(xm_win, 8, 3, "7) (external)");
  1421. X    mvwaddstr(xm_win, 11, 3, "<ESC> to Abort");
  1422. X    mvwaddstr(xm_win, 13, 3, "Protocol:");
  1423. X    box(xm_win, VERT, HORZ);
  1424. X    if (up)
  1425. X        mvwattrstr(xm_win, 0, 6, A_BOLD, " Upload ");
  1426. X    else
  1427. X        mvwattrstr(xm_win, 0, 5, A_BOLD, " Download ");
  1428. X
  1429. X    wmove(xm_win, 13, 13);
  1430. X    wrefresh(xm_win);
  1431. X                    /* get the protocol */
  1432. X    while ((type = get_num(xm_win, 1)) != -1) {
  1433. X        if (type >= 1 && type <= PROTOCOLS)
  1434. X            break;
  1435. X        beep();
  1436. X        mvwaddch(xm_win, 13, 13, (chtype) ' ');
  1437. X        wmove(xm_win, 13, 13);
  1438. X        wrefresh(xm_win);
  1439. X    }
  1440. X    type--;
  1441. X    werase(xm_win);
  1442. X    wrefresh(xm_win);
  1443. X    delwin(xm_win);
  1444. X                    /* chickened out */
  1445. X    if (type < 0)
  1446. X        return(0);
  1447. X
  1448. X    if (fd == -1) {
  1449. X        error_win(0, "Not currently connected to any host", "");
  1450. X        return(0);
  1451. X    }
  1452. X                    /* is the external protocol? */
  1453. X    if (type == EXTRNL) {
  1454. X                    /* get the command line */
  1455. X        if (!(list = get_extrnl(up)))
  1456. X            return(0);
  1457. X        extrnl(list);
  1458. X        return(1);
  1459. X    }
  1460. X                    /* is a batch protocol? */
  1461. X    is_batch = 0;
  1462. X    switch (type) {
  1463. X        case MODEM7:
  1464. X        case YMODEM:
  1465. X        case YMODEM_G:
  1466. X            is_batch++;
  1467. X            break;
  1468. X        default:
  1469. X            break;
  1470. X    }
  1471. X
  1472. X    /*
  1473. X     * When receiving files in one of the batch modes, there is no
  1474. X     * need to prompt for a list of file names.
  1475. X     */
  1476. X    list = null_ptr;
  1477. X    if (up || !is_batch) {
  1478. X        if (!(list = get_names(up, type, is_batch)))
  1479. X            return(0);
  1480. X    }
  1481. X                    /* if ascii transfer */
  1482. X    if (type == XASCII) {
  1483. X        xfer_ascii(list, up);
  1484. X        free_ptr(list);
  1485. X        if (up)
  1486. X            return(0);
  1487. X        return(1);
  1488. X    }
  1489. X    xfer_win(list, up, type);
  1490. X    free_ptr(list);
  1491. X    return(1);
  1492. X}
  1493. X
  1494. Xchar *protocol[PROTOCOLS] = {"xmodem", "xmodem-1k", "modem7", "ymodem",
  1495. X    "ymodem-g", "ASCII", "(external)"};
  1496. X
  1497. X/*
  1498. X * Prompt for a list of files for the transfer programs.  A NULL return
  1499. X * code means you chickened out.
  1500. X */
  1501. X
  1502. Xstatic char *
  1503. Xget_names(up, type, is_batch)
  1504. Xint up, type, is_batch;
  1505. X{
  1506. X    int can;
  1507. X    WINDOW *gn_win, *newwin();
  1508. X    char *list, *ans, *file, buf[40], *expand(), *get_str(), *strtok();
  1509. X    void st_line();
  1510. X    struct stat stbuf;
  1511. X
  1512. X    touchwin(stdscr);
  1513. X    refresh();
  1514. X    st_line("");
  1515. X
  1516. X    gn_win = newwin(7, 70, 5, 5);
  1517. X    mvwaddstr(gn_win, 3, 4, "Enter filename: ");
  1518. X    box(gn_win, VERT, HORZ);
  1519. X    if (up)
  1520. X        sprintf(buf, " Send %s ", protocol[type]);
  1521. X    else
  1522. X        sprintf(buf, " Receive %s ", protocol[type]);
  1523. X    mvwattrstr(gn_win, 0, 3, A_BOLD, buf);
  1524. X
  1525. X    while (1) {
  1526. X        wmove(gn_win, 3, 20);
  1527. X        wrefresh(gn_win);
  1528. X                    /* get the answers */
  1529. X        if (is_batch)
  1530. X            ans = get_str(gn_win, 60, "", "");
  1531. X        else
  1532. X            ans = get_str(gn_win, 60, "", "     ");
  1533. X
  1534. X        if (ans == NULL || *ans == NULL) {
  1535. X            list = NULL;
  1536. X            break;
  1537. X        }
  1538. X        list = expand(ans);
  1539. X
  1540. X        if (is_batch)
  1541. X            break;
  1542. X        /*
  1543. X         * Here we have the opportunity to determine the read and
  1544. X         * write permissions before things get started.  Much nicer
  1545. X         * than finding out later when there's no way to fix it.
  1546. X         */
  1547. X        file = strtok(list, "     ");
  1548. X                    /* sanity checking */
  1549. X        if (!stat(file, &stbuf)) {
  1550. X            if ((stbuf.st_mode & S_IFREG) != S_IFREG) {
  1551. X                beep();
  1552. X                clear_line(gn_win, 4, 15, 1);
  1553. X                mvwattrstr(gn_win, 4, 15, A_BOLD, "Not a regular file");
  1554. X                wrefresh(gn_win);
  1555. X                wait_key(gn_win, 3);
  1556. X                clear_line(gn_win, 4, 15, 1);
  1557. X                clear_line(gn_win, 3, 20, 1);
  1558. X                continue;
  1559. X            }
  1560. X        }
  1561. X                    /* check read permission */
  1562. X        if (up) {
  1563. X            if (access(file, 0)) {
  1564. X                beep();
  1565. X                mvwattrstr(gn_win, 4, 15, A_BOLD, "Can't find file");
  1566. X                wrefresh(gn_win);
  1567. X                wait_key(gn_win, 3);
  1568. X                clear_line(gn_win, 4, 15, 1);
  1569. X                clear_line(gn_win, 3, 20, 1);
  1570. X                continue;
  1571. X            }
  1572. X            if (access(file, 4)) {
  1573. X                beep();
  1574. X                mvwattrstr(gn_win, 4, 15, A_BOLD, "No read permission");
  1575. X                wrefresh(gn_win);
  1576. X                wait_key(gn_win, 3);
  1577. X                clear_line(gn_win, 4, 15, 1);
  1578. X                clear_line(gn_win, 3, 20, 1);
  1579. X                continue;
  1580. X            }
  1581. X            break;
  1582. X        }
  1583. X                    /* check write permission */
  1584. X        if (!(can = can_write(file))) {
  1585. X            beep();
  1586. X            clear_line(gn_win, 4, 15, 1);
  1587. X            mvwattrstr(gn_win, 4, 15, A_BOLD, "No write permission");
  1588. X            wrefresh(gn_win);
  1589. X            wait_key(gn_win, 3);
  1590. X            clear_line(gn_win, 4, 15, 1);
  1591. X            clear_line(gn_win, 3, 20, 1);
  1592. X            continue;
  1593. X        }
  1594. X        if (can == 2) {
  1595. X            if (!yes_prompt(gn_win, 4, 15, A_BOLD, "File exists, overwrite")) {
  1596. X                clear_line(gn_win, 4, 15, 1);
  1597. X                clear_line(gn_win, 3, 20, 1);
  1598. X                continue;
  1599. X            }
  1600. X            break;
  1601. X        }
  1602. X        break;
  1603. X    }
  1604. X    werase(gn_win);
  1605. X    wrefresh(gn_win);
  1606. X    delwin(gn_win);
  1607. X
  1608. X    return(list);
  1609. X}
  1610. X
  1611. X/*
  1612. X * Prompt for the Unix command line to be used as an external file
  1613. X * transfer program.  A return code of NULL means forget it.
  1614. X */
  1615. X
  1616. Xstatic char *
  1617. Xget_extrnl(up)
  1618. Xint up;
  1619. X{
  1620. X    WINDOW *ge_win, *newwin();
  1621. X    char *cmd, *ans, *get_str(), *expand();
  1622. X    void st_line();
  1623. X
  1624. X    touchwin(stdscr);
  1625. X    refresh();
  1626. X    st_line("");
  1627. X                    /* prompt for command line */
  1628. X    ge_win = newwin(7, 70, 5, 5);
  1629. X    mvwaddstr(ge_win, 3, 4, "Enter Unix command: ");
  1630. X    box(ge_win, VERT, HORZ);
  1631. X    if (up)
  1632. X        mvwattrstr(ge_win, 0, 3, A_BOLD, " Send (external) ");
  1633. X    else
  1634. X        mvwattrstr(ge_win, 0, 3, A_BOLD, " Receive (external) ");
  1635. X    wmove(ge_win, 3, 24);
  1636. X    wrefresh(ge_win);
  1637. X                    /* get the line */
  1638. X    ans = get_str(ge_win, 60, "", "");
  1639. X    cmd = expand(ans);
  1640. X    if (*cmd == NULL)
  1641. X        cmd = NULL;
  1642. X
  1643. X    werase(ge_win);
  1644. X    wrefresh(ge_win);
  1645. X    delwin(ge_win);
  1646. X    return(cmd);
  1647. X}
  1648. SHAR_EOF
  1649. if test 5812 -ne "`wc -c < 'x_menu.c'`"
  1650. then
  1651.     echo shar: "error transmitting 'x_menu.c'" '(should have been 5812 characters)'
  1652. fi
  1653. fi
  1654. echo shar: "extracting 'x_rcv.c'" '(11805 characters)'
  1655. if test -f 'x_rcv.c'
  1656. then
  1657.     echo shar: "will not over-write existing file 'x_rcv.c'"
  1658. else
  1659. sed 's/^X//' << \SHAR_EOF > 'x_rcv.c'
  1660. X/*
  1661. X * Receive a list of files using a version of Ward Christensen's file
  1662. X * transfer protocol.  A return code of 1 means the user must acknowledge
  1663. X * an error condition (a user generated abort returns a 0).  Write errors
  1664. X * are considered fatal.
  1665. X */
  1666. X
  1667. X#include <stdio.h>
  1668. X#include <curses.h>
  1669. X#include "config.h"
  1670. X#include "dial_dir.h"
  1671. X#include "misc.h"
  1672. X#include "xmodem.h"
  1673. X
  1674. Xunsigned char buf[1029];
  1675. Xchar file_name[15];
  1676. Xlong file_length;
  1677. X
  1678. Xstatic int err_method, tot_err, block_size;
  1679. X
  1680. Xint
  1681. Xrcv_xmodem(win, list, type, fast)
  1682. XWINDOW *win;
  1683. Xchar *list;
  1684. Xint type, fast;
  1685. X{
  1686. X    extern char *protocol[];
  1687. X    FILE *fp, *my_fopen();
  1688. X    int i, default_err, is_batch, max_block, code, file_count, got_hdr;
  1689. X    int hours, mins, secs, len;
  1690. X    long block, recv;
  1691. X    float percent, performance;
  1692. X    unsigned char blk;
  1693. X    unsigned int sleep();
  1694. X    char *file, *name, *strcpy(), *strrchr(), *strtok();
  1695. X    void cancel_xfer();
  1696. X                    /* which protocol? */
  1697. X    switch (type) {
  1698. X        case XMODEM:
  1699. X            default_err = CRC_CHECKSUM;
  1700. X            is_batch = 0;
  1701. X            max_block = 128;
  1702. X            break;
  1703. X        case XMODEM_1k:
  1704. X            default_err = CRC_CHECKSUM;
  1705. X            is_batch = 0;
  1706. X            max_block = 1024;
  1707. X            break;
  1708. X        case MODEM7:
  1709. X            default_err = CHECKSUM;
  1710. X            is_batch = 1;
  1711. X            max_block = 128;
  1712. X            break;
  1713. X        case YMODEM:
  1714. X            default_err = CRC;
  1715. X            is_batch = 1;
  1716. X            max_block = 1024;
  1717. X            performance = 1.09;
  1718. X            break;
  1719. X        case YMODEM_G:
  1720. X            default_err = NONE;
  1721. X            is_batch = 1;
  1722. X            max_block = 1024;
  1723. X            performance = 1.02;
  1724. X            break;
  1725. X        default:
  1726. X            return(1);
  1727. X    }
  1728. X
  1729. X    tot_err = 0;
  1730. X    file_count = 0;
  1731. X    mvwaddstr(win, 2, 24, protocol[type]);
  1732. X    mvwaddstr(win, 11, 24, "0  ");
  1733. X
  1734. X    while (1) {
  1735. X        file_count++;
  1736. X        file_length = 0L;
  1737. X                    /* user supplied name */
  1738. X        if (!is_batch) {
  1739. X            if (file_count > 1)
  1740. X                break;
  1741. X
  1742. X            file = strtok(list, "     ");
  1743. X                    /* dissect the file name */
  1744. X            if ((name = strrchr(file, '/')))
  1745. X                strcpy(file_name, name++);
  1746. X            else
  1747. X                strcpy(file_name, file);
  1748. X        }
  1749. X                    /* get the modem7 file name */
  1750. X        if (type == MODEM7) {
  1751. X            if (code = rcv_modem7(win, default_err))
  1752. X                return(code +1);
  1753. X
  1754. X            file = file_name;
  1755. X        }
  1756. X                    /* get the block 0 */
  1757. X        if (type == YMODEM || type == YMODEM_G) {
  1758. X            if (code = send_first(win, max_block, default_err))
  1759. X                return(code +1);
  1760. X
  1761. X            if (code = rcv_ymodem(win))
  1762. X                return(code +1);
  1763. X
  1764. X                    /* at the end? */
  1765. X            if (buf[3] == NULL) {
  1766. X                beep();
  1767. X                wrefresh(win);
  1768. X                putc_line(ACK);
  1769. X                sleep(1);
  1770. X                return(0);
  1771. X            }
  1772. X            file = file_name;
  1773. X        }
  1774. X                    /* any trouble? */
  1775. X        if (file_name[0] == NULL)
  1776. X            continue;
  1777. X
  1778. X        clear_line(win, 3, 24, 1);
  1779. X        waddstr(win, file_name);
  1780. X                    /* if file length is known */
  1781. X        if (file_length != 0L) {
  1782. X            mvwprintw(win, 4, 24, "%-10ld", file_length);
  1783. X
  1784. X            secs = (file_length * 10.0 / dir->baud[dir->d_cur]) * performance;
  1785. X            hours = secs / 3600;
  1786. X            mins = (secs % 3600) / 60;
  1787. X            secs = (secs % 3600) % 60;
  1788. X
  1789. X            mvwprintw(win, 6, 24, "%d:%02d:%02d", hours, mins, secs);
  1790. X        }
  1791. X                    /* some starting numbers */
  1792. X        mvwaddstr(win, 7, 24, "0    ");
  1793. X        if (file_length != 0L && fast)
  1794. X            mvwaddstr(win, 8, 24, "0%  ");
  1795. X        if (fast)
  1796. X            mvwaddstr(win, 9, 24, "0          ");
  1797. X        mvwaddstr(win, 10, 24, "0 ");
  1798. X        clear_line(win, 12, 24, 1);
  1799. X        waddstr(win, "NONE");
  1800. X        wrefresh(win);
  1801. X
  1802. X        /*
  1803. X         * If the user supplied the name, write permission is checked
  1804. X         * by the get_names() routine in xfer_menu().  If modem7
  1805. X         * or ymodem supplied name, the name is unique and the write
  1806. X         * permission on the directory is checked by the change_name()
  1807. X         * routines.  So why is this here?
  1808. X         */
  1809. X                    /* open the file */
  1810. X        if (!(fp = my_fopen(file, "w"))) {
  1811. X            beep();
  1812. X            clear_line(win, 12, 24, 1);
  1813. X            wattrstr(win, A_BOLD, "CAN'T OPEN FILE");
  1814. X            wrefresh(win);
  1815. X            cancel_xfer(1);
  1816. X            return(1);
  1817. X        }
  1818. X                    /* ACK the block 0 */
  1819. X        if (type == YMODEM || type == YMODEM_G)
  1820. X            putc_line(ACK);
  1821. X
  1822. X        if (code = send_first(win, max_block, default_err)) {
  1823. X            fclose(fp);
  1824. X            return(code +1);
  1825. X        }
  1826. X                    /* here we go... */
  1827. X        clear_line(win, 12, 24, 1);
  1828. X        waddstr(win, "NONE");
  1829. X        wrefresh(win);
  1830. X        blk = 1;
  1831. X        block = 1L;
  1832. X        recv = 0L;
  1833. X        got_hdr = 1;
  1834. X        while (1) {
  1835. X            code = rcv_block(win, got_hdr, max_block, blk);
  1836. X
  1837. X            if (code < 0) {
  1838. X                fclose(fp);
  1839. X                return(code +1);
  1840. X            }
  1841. X            got_hdr = 0;
  1842. X                    /* are we done? */
  1843. X            if (buf[0] == EOT) {
  1844. X                if (!is_batch) {
  1845. X                    beep();
  1846. X                    wrefresh(win);
  1847. X                    sleep(1);
  1848. X                }
  1849. X                break;
  1850. X            }
  1851. X                    /* if not a duplicate block */
  1852. X            if (!code) {
  1853. X                if (file_length != 0L) {
  1854. X                    len = file_length - recv;
  1855. X                    if (len > block_size)
  1856. X                        len = block_size;
  1857. X                }
  1858. X                else
  1859. X                    len = block_size;
  1860. X
  1861. X                if (fwrite((char *) &buf[3], sizeof(char), len, fp) != len) {
  1862. X                    beep();
  1863. X                    clear_line(win, 12, 24, 1);
  1864. X                    wattrstr(win, A_BOLD, "WRITE ERROR");
  1865. X                    wrefresh(win);
  1866. X                    cancel_xfer(1);
  1867. X                    fclose(fp);
  1868. X                    /* fatal */
  1869. X                    return(1);
  1870. X                }
  1871. X                mvwprintw(win, 7, 24, "%-5ld", block);
  1872. X                recv = recv + (unsigned int) len;
  1873. X                if (fast)
  1874. X                    mvwprintw(win, 9, 24, "%-10ld", recv);
  1875. X                blk++;
  1876. X                block++;
  1877. X            }
  1878. X            /*
  1879. X             * If the length is known, give the same status
  1880. X             * report as uploading
  1881. X             */
  1882. X            if (file_length != 0L && fast) {
  1883. X                percent = recv * 100.0 / file_length;
  1884. X                if (percent > 100.0)
  1885. X                    percent = 100.0;
  1886. X                mvwprintw(win, 8, 24, "%0.1f%%", percent);
  1887. X            }
  1888. X            wrefresh(win);
  1889. X            putc_line(ACK);
  1890. X        }
  1891. X        if (file_length != 0L && fast) {
  1892. X            mvwaddstr(win, 8, 24, "100%  ");
  1893. X            wrefresh(win);
  1894. X        }
  1895. X        /*
  1896. X         * If the file length is not known, search backwards from
  1897. X         * the end of the file until you find a character that is
  1898. X         * not the ^Z padding character.
  1899. X         */
  1900. X        if (file_length == 0L) {
  1901. X            for (i=block_size+2; i>2; i--) {
  1902. X                if (buf[i] != CTRLZ)
  1903. X                    break;
  1904. X            }
  1905. X            file_length = recv - (unsigned int) block_size + (unsigned int) i -2L;
  1906. X            fclose(fp);
  1907. X            if (fix_length(file_name, file_length)) {
  1908. X                beep();
  1909. X                clear_line(win, 12, 24, 1);
  1910. X                wattrstr(win, A_BOLD, "TRUNCATE ERROR");
  1911. X                wrefresh(win);
  1912. X                    /* fatal */
  1913. X                return(1);
  1914. X            }
  1915. X        }
  1916. X        else
  1917. X            fclose(fp);
  1918. X                    /* ACK the EOT */
  1919. X        putc_line(ACK);
  1920. X    }
  1921. X    return(0);
  1922. X}
  1923. X
  1924. X/*
  1925. X * Send the first character to start the transmission and set the error
  1926. X * checking method.  Returns the standard error codes or 0 on success.
  1927. X * The variables err_method and block_size are global.
  1928. X */
  1929. X
  1930. Xstatic int
  1931. Xsend_first(win, max_block, default_err)
  1932. XWINDOW *win;
  1933. Xint max_block, default_err;
  1934. X{
  1935. X    int i, err_count;
  1936. X    unsigned int sleep();
  1937. X    void cancel_xfer();
  1938. X                    /* default error method */
  1939. X    err_method = default_err;
  1940. X    if (default_err == CRC_CHECKSUM)
  1941. X        err_method = CRC;
  1942. X                    /* send the first char */
  1943. X    err_count = 0;
  1944. X    while (err_count < MAX_ERRORS*2) {
  1945. X        mvwprintw(win, 10, 24, "%-2d", err_count);
  1946. X
  1947. X                    /* check for keyboard abort */
  1948. X        if (wgetch(win) == ESC) {
  1949. X            beep();
  1950. X            clear_line(win, 12, 24, 1);
  1951. X            waddstr(win, "ABORTED");
  1952. X            wrefresh(win);
  1953. X            cancel_xfer(1);
  1954. X            sleep(3);
  1955. X            return(ABORT);
  1956. X        }
  1957. X                    /* switch to checksum? */
  1958. X        if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
  1959. X            err_method = CHECKSUM;
  1960. X
  1961. X                    /* send error method code */
  1962. X        clear_line(win, 5, 24, 1);
  1963. X        switch (err_method) {
  1964. X            case CHECKSUM:
  1965. X                waddstr(win, "CHECKSUM");
  1966. X                putc_line(NAK);
  1967. X                break;
  1968. X            case CRC:
  1969. X                waddstr(win, "CRC");
  1970. X                putc_line('C');
  1971. X                break;
  1972. X            case NONE:
  1973. X                waddstr(win, "NONE");
  1974. X                putc_line('G');
  1975. X                break;
  1976. X        }
  1977. X        /*
  1978. X         * We've cut the delay time in half, so we double
  1979. X         * the allowable errors
  1980. X         */
  1981. X        if ((i = getc_line(5)) == -1) {
  1982. X            err_count++;
  1983. X            clear_line(win, 12, 24, 1);
  1984. X            waddstr(win, "NO RESPONSE");
  1985. X            wrefresh(win);
  1986. X            continue;
  1987. X        }
  1988. X        buf[0] = i;
  1989. X#ifdef DEBUG
  1990. X        fprintf(stderr, "send_first: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
  1991. X#endif /* DEBUG */
  1992. X
  1993. X        switch (buf[0]) {
  1994. X            case SOH:    /* small block follows */
  1995. X                block_size = 128;
  1996. X                return(0);
  1997. X            case STX:    /* large block follows */
  1998. X                if (max_block == 1024) {
  1999. X                    block_size = 1024;
  2000. X                    return(0);
  2001. X                }
  2002. X                /* fall thru */
  2003. X            default:
  2004. X                err_count++;
  2005. X                clear_line(win, 12, 24, 1);
  2006. X                waddstr(win, "BAD HEADER");
  2007. X                wrefresh(win);
  2008. X                    /* read some garbage... */
  2009. X                fread_line(buf, 1028, 3);
  2010. X                putc_line(NAK);
  2011. X                break;
  2012. X        }
  2013. X    }
  2014. X    beep();
  2015. X    clear_line(win, 12, 24, 1);
  2016. X    wattrstr(win, A_BOLD, "TIMED OUT");
  2017. X    wrefresh(win);
  2018. X    return(ERROR);
  2019. X}
  2020. X
  2021. X/*
  2022. X * Receive a block of info from the host.  Returns a 0 on success, a 1 on
  2023. X * a duplicate block or the standard error codes.  The variables
  2024. X * err_method and block_size are global.
  2025. X */
  2026. X
  2027. Xint
  2028. Xrcv_block(win, got_hdr, max_block, blk)
  2029. XWINDOW *win;
  2030. Xint got_hdr, max_block;
  2031. Xunsigned char blk;
  2032. X{
  2033. X    int i, err_count, bad_block, out_of_sync;
  2034. X    unsigned short crc, calc_crc();
  2035. X    unsigned int packet, sleep();
  2036. X    unsigned char calc_sum(), crc_1, crc_2;
  2037. X    void cancel_xfer();
  2038. X
  2039. X    err_count = 0;
  2040. X    while (err_count < MAX_ERRORS) {
  2041. X        mvwprintw(win, 10, 24, "%-2d", err_count);
  2042. X        mvwprintw(win, 11, 24, "%-3d", tot_err);
  2043. X
  2044. X                    /* scan the keyboard for abort */
  2045. X        if (wgetch(win) == ESC) {
  2046. X            beep();
  2047. X            clear_line(win, 12, 24, 1);
  2048. X            waddstr(win, "ABORTED");
  2049. X            wrefresh(win);
  2050. X            cancel_xfer(1);
  2051. X            sleep(3);
  2052. X            return(ABORT);
  2053. X        }
  2054. X                    /* have we already got a hdr? */
  2055. X        if (!got_hdr) {
  2056. X            if ((i = getc_line(10)) == -1) {
  2057. X                err_count++;
  2058. X                tot_err++;
  2059. X                clear_line(win, 12, 24, 1);
  2060. X                waddstr(win, "NO RESPONSE");
  2061. X                wrefresh(win);
  2062. X                continue;
  2063. X            }
  2064. X            buf[0] = i;
  2065. X#ifdef DEBUG
  2066. X            fprintf(stderr, "rcv_block: got header %02x, %03o, %d\n", buf[0], buf[0], buf[0]);
  2067. X#endif /* DEBUG */
  2068. X                    /* what'd we get? */
  2069. X            switch (buf[0]) {
  2070. X                case EOT:    /* we're done! */
  2071. X                    clear_line(win, 12, 24, 1);
  2072. X                    waddstr(win, "TRANSFER COMPLETE");
  2073. X                    wrefresh(win);
  2074. X                    sleep(1);
  2075. X                    return(0);
  2076. X                case SOH:    /* small block follows */
  2077. X                    block_size = 128;
  2078. X                    break;
  2079. X                case STX:    /* large block follows */
  2080. X                    if (max_block == 1024) {
  2081. X                        block_size = 1024;
  2082. X                        break;
  2083. X                    }
  2084. X                    /* fall thru... */
  2085. X                default:
  2086. X                    err_count++;
  2087. X                    tot_err++;
  2088. X                    clear_line(win, 12, 24, 1);
  2089. X                    waddstr(win, "BAD HEADER");
  2090. X                    wrefresh(win);
  2091. X
  2092. X                    /* flush a bad packet */
  2093. X                    fread_line(buf, 1028, 5);
  2094. X                    putc_line(NAK);
  2095. X                    continue;
  2096. X            }
  2097. X        }
  2098. X        got_hdr = 0;
  2099. X                    /* read the rest of the packet */
  2100. X        packet = block_size + 2 + (err_method == CHECKSUM ? 1 : 2);
  2101. X        if (fread_line(&buf[1], packet, 10) == -1) {
  2102. X            clear_line(win, 12, 24, 1);
  2103. X            waddstr(win, "TIMED OUT");
  2104. X            wrefresh(win);
  2105. X            putc_line(NAK);
  2106. X            err_count++;
  2107. X            tot_err++;
  2108. X            continue;
  2109. X        }
  2110. X
  2111. X        /*
  2112. X         * Validation of the packet includes checking the
  2113. X         * block number, its complement, and the crc/checksum.
  2114. X         */
  2115. X        out_of_sync = 0;
  2116. X        if (buf[1] != blk || buf[2] != (unsigned char) ~blk)
  2117. X            out_of_sync++;
  2118. X
  2119. X        bad_block = 0;
  2120. X        switch (err_method) {
  2121. X            case CHECKSUM:
  2122. X#ifdef DEBUG
  2123. X                fprintf(stderr, "blk=%d, checksum=%d\n", blk, calc_sum(&buf[3], block_size));
  2124. X#endif /* DEBUG */
  2125. X                if (buf[block_size +3] != calc_sum(&buf[3], block_size))
  2126. X                    bad_block++;
  2127. X                break;
  2128. X            case CRC:
  2129. X                crc = calc_crc(&buf[3], block_size);
  2130. X                crc_1 = crc >> 8;
  2131. X                crc_2 = crc;
  2132. X#ifdef DEBUG
  2133. X                fprintf(stderr, "blk=%d, crc1=%d, crc2=%d\n", blk, crc_1, crc_2);
  2134. X#endif /* DEBUG */
  2135. X                if (buf[block_size +3] != crc_1 || buf[block_size +4] != crc_2)
  2136. X                    bad_block++;
  2137. X                break;
  2138. X            case NONE:
  2139. X                return(0);
  2140. X        }
  2141. X                    /* handle errors */
  2142. X        if (bad_block) {
  2143. X            clear_line(win, 12, 24, 1);
  2144. X            if (err_method == CRC)
  2145. X                waddstr(win, "CRC FAILED");
  2146. X            else
  2147. X                waddstr(win, "CHECKSUM FAILED");
  2148. X            wrefresh(win);
  2149. X            putc_line(NAK);
  2150. X            err_count++;
  2151. X            tot_err++;
  2152. X            continue;
  2153. X        }
  2154. X                    /* not really an error */
  2155. X        if (out_of_sync) {
  2156. X            /*
  2157. X             * If a perfect packet is off by 1 block number,
  2158. X             * (a lost ACK could cause this) then treat it as
  2159. X             * a good block but don't write it to disk.
  2160. X             */
  2161. X            if (buf[1] == (unsigned char) blk-1)
  2162. X                return(1);
  2163. X
  2164. X            clear_line(win, 12, 24, 1);
  2165. X            waddstr(win, "OUT OF SYNC");
  2166. X            wrefresh(win);
  2167. X            putc_line(NAK);
  2168. X            err_count++;
  2169. X            tot_err++;
  2170. X            continue;
  2171. X        }
  2172. X        return(0);
  2173. X    }
  2174. X    beep();
  2175. X    clear_line(win, 12, 24, 1);
  2176. X    waddstr(win, "TOO MANY ERRORS");
  2177. X    wrefresh(win);
  2178. X    cancel_xfer(1);
  2179. X    return(ERROR);
  2180. X}
  2181. SHAR_EOF
  2182. if test 11805 -ne "`wc -c < 'x_rcv.c'`"
  2183. then
  2184.     echo shar: "error transmitting 'x_rcv.c'" '(should have been 11805 characters)'
  2185. fi
  2186. fi
  2187. exit 0
  2188. #    End of shell archive
  2189.  
  2190. -- 
  2191. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  2192.